﻿#include "MainWnd.h"
#include <QTimer>
#include <QTimerEvent>
#include <QDateTime>
#include <QGraphicsView>
#include <QGraphicsScene>

#include <regex>

#include "COperLogManager.h"
#include "COrderManager.h"
#include "CabinetManager.h"
#include "CAudioBroadcast.h"
#include "custom/CToastBox.h"
#include "AppModel.h"
#include "IPlatformProxyInterface.h"
#include "CPlatformProxyFactory.h"
#include "CPaymentManager.h"
#include "IPayplatInterface.h"
#include "IValidatorInterface.h"
#include "CValidatorFactory.h"

#include "AppModel.h"

// 支付方式
#define PAYMODE_ALIPAY      "2"
#define PAYMODE_WECHATPAY   "1"
#define PAYMODE_CASH        "0"
#define PAYMODE_ONECODE     "9"

struct MainWnd::SessionImpl
{
    zl::Order order;
    zl::PaidDetail paid;
    zl::OperLog log;
};

MainWnd::MainWnd(QWidget *parent)
    : QWidget(parent)
    , ewf_current_(EWF_Unknow)
    , mode_current_(EWorkMode_Normal)
    , timer_(new QTimer(this))
    , timer_cnt_(0)
    , timer_flag_(false)
    , timer_payplat_(new QTimer(this))
    , session_(new SessionImpl)
{
    setAttribute(Qt::WA_StyledBackground);
    ui.setupUi(this);

    init_view();
    init_timer();

    auto factory = new zl::CPlatformProxyFactory;
    plat_api_ = factory->get();
    auto factory1 = new zl::CValidatorFactory;
    validator_ = factory1->getValidator(APPMODEL()->CabinetInfo().validator_type);
}

MainWnd::~MainWnd()
{
    timer_->stop();
}

void MainWnd::EventRequestOrderDetails(const std::string& order_id, const std::string& cabinetno, int32_t boxno)
{
    if (ewf_current_ != EWF_FetchAuthPwd)
    {
        return;
    }

    // 未找到订单信息或查询失败
    if (cabinetno == "0")
    {
        CToastBox::Error(this, tr("Operation failed"), tr("Wrong phone no or password"));
        return;
    }

    // 提示用户可能正确的柜子编号
    CToastBox::Info(this, "",
        tr("There is no order found in current cabinet, you may try in those cabinets below [%1]")
        .arg(cabinetno.c_str()));
    return;
}

void MainWnd::EventPayplatReply(const zl::PayReply &reply, int code)
{
    if (ewf_current_ != EWF_PayInfo)
    {
        // 当前不是等待支付结果页面，不处理支付结果
        return;
    }

    switch (reply.type)
    {
    case zl::EPayRequestTypeCreate:     // 创建订单回复
    {
        if (code != zl::EPayError_Success || reply.order_id != session_->paid.pay_order_id || reply.retcode != "0000")
        {
            // 创建支付请求失败
            ui.lb_pay_tips->setText(tr("Request qrcode failed"));
            return;
        }

        // 加载二维码图片
        char *buf = nullptr;
        int32_t size = 0;
        QPixmap pix;
        zl::GetPayplatInterface()->GetQRCode(reply.img_url, &buf, size);
        if (!pix.loadFromData((unsigned char*)buf, size))
        {
            // 加载二维码图片失败
            ui.lb_pay_tips->setText(tr("Request qrcode failed"));
            return;
        }
        ui.lb_qrcode->setPixmap(pix);

        // 加载二维码成功，开启定时器定时查询支付结果
        // 保存创建好的支付订单的支付金额和交易单号
        session_->paid.fee_total = QString(reply.total_fee.c_str()).toInt();
        session_->paid.pay_trade_no = reply.out_trade_no;
        session_->paid.pay_prepay_id = reply.prepay_id;
        ui.lb_amount_total->setText(tr("%1 yuan").arg((float)session_->paid.fee_total / 100.0));
        ui.lb_pay_tips->setText(tr("Waiting for payment..."));
        timer_payplat_->stop();
        timer_payplat_->start();
        break;
    }
    case zl::EPayRequestTypeCheck:      // 查询订单回复
    {
        // 查询订单请求失败
        if (code != zl::EPayError_Success || reply.order_id != session_->paid.pay_order_id)
        {
            return;
        }

        // 未支付或其他错误
        if (reply.retcode != "0000" || reply.pay_state != "01")
        {
            return;
        }

        // 支付成功
        if(reply.pay_type == "00")  //alipay
        {
            session_->paid.pay_mode = PAYMODE_ALIPAY;
        }
        else if(reply.pay_type == "01")
        {
            session_->paid.pay_mode = PAYMODE_WECHATPAY;
        }
        else
        {
            session_->paid.pay_mode = PAYMODE_ONECODE;
        }

        session_->paid.pay_prepay_id = reply.prepay_id;
        session_->paid.fee_paid = std::stoi(reply.total_fee);
        ui.lb_pay_tips->setText(tr("Payment successful"));
        // 停止支付定时器
        timer_payplat_->stop();
        // 保存支付记录跳转页面
        payment_complete();
        break;
    }
    default:
        return;
    }
}

void MainWnd::EventITLEventCredit(int value, QString currency)
{
    if (ewf_current_ != EWF_PayInfo)
    {
        return;
    }

    // 更新已付金额记录
    session_->paid.fee_paid += value;
    ui.lb_amount_paid->setText(tr("%1 yuan").arg((double)session_->paid.fee_paid / 100.0));

    // 未支付足够的金额
    if (session_->paid.fee_paid < session_->paid.fee_total)
    {
        return;
    }

    // 支付完成，关闭纸币器
    if (validator_ != nullptr)
    {
        validator_->Disable();
    }

    // 跳转页面
    payment_complete();
}

void MainWnd::back_to_home()
{
    // 停止纸币器
    timer_payplat_->stop();
    if (validator_ != nullptr)
    {
        validator_->Disable();
    }

    // 支付流程异常终止，记录当前已支付的金额
    if (ewf_current_ == EWF_PayInfo)
    {
        payment_complete(false);
    }

    // 停止语音播放
    zl::CAudioBroadcast::Instance()->Stop();

    // 返回首页
    timer_->stop();
    mode_current_ = EWorkMode_Normal;
    ewf_current_ = EWF_Unknow;
    ewf_stack_.clear();
    emit backToHome();
}

void MainWnd::back_to_last_view()
{
    if (ewf_stack_.isEmpty())
    {
        back_to_home();
        return;
    }

    auto ewf = ewf_stack_.pop();
    set_current_status(ewf, true);
}

void MainWnd::start_to_deposit()
{
    set_current_status(EWF_DepositSelectSize);
}

void MainWnd::start_to_fetch()
{
    set_current_status(EWF_FetchAuthPwd);
}

void MainWnd::event_numpad_key_clicked(const QString &key)
{
    QLineEdit* edt = qobject_cast<QLineEdit*>(this->focusWidget());
    if (edt == nullptr)
    {
        return;
    }

    edt->setText(edt->text() + key);
}

void MainWnd::event_numpad_del_clicked()
{
    ui.edt_set_no->clear();
    ui.edt_set_pwd->clear();
    ui.edt_confirm_no->clear();
    ui.edt_confirm_pwd->clear();
    ui.edt_fetch_auth_no->clear();
    ui.edt_fetch_auth_pwd->clear();
}

void MainWnd::event_numpad_ok_clicked()
{
    switch (ewf_current_)
    {
    case EWF_DepositSetNo:
        set_no_finished();
        break;
    case EWF_DepositSetPwd:
        set_pwd_finished();
        break;
    case EWF_FetchAuthPwd:
        get_auth_finished();
        break;
    default:
        return;
    }
}

void MainWnd::event_input_edt_text_changed()
{
    switch (ewf_current_)
    {
    case EWF_DepositSetNo:
    {
        if (ui.edt_set_no->text().size() >= 4)
        {
            ui.edt_confirm_no->text().size() >= 4 ? set_no_finished() : ui.edt_confirm_no->setFocus();
        }
        else if (ui.edt_confirm_no->text().size() >= 4)
        {
            ui.edt_set_no->setFocus();
        }
        break;
    }
    case EWF_DepositSetPwd:
    {
        if (ui.edt_set_pwd->text().size() >= 6 )
        {
            ui.edt_confirm_pwd->text().size() >= 6 ? set_pwd_finished() : ui.edt_confirm_pwd->setFocus();
        }
        else if (ui.edt_confirm_pwd->text().size() >= 6)
        {
            ui.edt_set_pwd->setFocus();
        }
        break;
    }
    case EWF_FetchAuthPwd:
    {
        if (ui.edt_fetch_auth_no->text().size() >= 4)
        {
            ui.edt_fetch_auth_pwd->text().size() >= 6 ? get_auth_finished() : ui.edt_fetch_auth_pwd->setFocus();
        }
        else if (ui.edt_fetch_auth_pwd->text().size() >= 6)
        {
            ui.edt_fetch_auth_no->setFocus();
        }
        break;
    }
    default:
        return;
    }
}

void MainWnd::init_view()
{
    // 绑定键盘事件
    connect(ui.wnd_numpad_set_no, &CCustomNumpad::key, this, &MainWnd::event_numpad_key_clicked);
    connect(ui.wnd_numpad_set_no, &CCustomNumpad::del, this, &MainWnd::event_numpad_del_clicked);
    connect(ui.wnd_numpad_set_no, &CCustomNumpad::ok, this, &MainWnd::event_numpad_ok_clicked);
    connect(ui.wnd_numpad_set_pwd, &CCustomNumpad::key, this, &MainWnd::event_numpad_key_clicked);
    connect(ui.wnd_numpad_set_pwd, &CCustomNumpad::del, this, &MainWnd::event_numpad_del_clicked);
    connect(ui.wnd_numpad_set_no, &CCustomNumpad::ok, this, &MainWnd::event_numpad_ok_clicked);
    connect(ui.wnd_numpad_fetch_auth, &CCustomNumpad::key, this, &MainWnd::event_numpad_key_clicked);
    connect(ui.wnd_numpad_fetch_auth, &CCustomNumpad::del, this, &MainWnd::event_numpad_del_clicked);
    connect(ui.wnd_numpad_fetch_auth, &CCustomNumpad::ok, this, &MainWnd::event_numpad_ok_clicked);
    connect(ui.edt_set_no, &QLineEdit::textChanged, this, &MainWnd::event_input_edt_text_changed);
    connect(ui.edt_confirm_no, &QLineEdit::textChanged, this, &MainWnd::event_input_edt_text_changed);
    connect(ui.edt_set_pwd, &QLineEdit::textChanged, this, &MainWnd::event_input_edt_text_changed);
    connect(ui.edt_confirm_pwd, &QLineEdit::textChanged, this, &MainWnd::event_input_edt_text_changed);
    connect(ui.edt_fetch_auth_no, &QLineEdit::textChanged, this, &MainWnd::event_input_edt_text_changed);
    connect(ui.edt_fetch_auth_pwd, &QLineEdit::textChanged, this, &MainWnd::event_input_edt_text_changed);

    // 返回按钮
    connect(ui.btn_back, &QPushButton::clicked, [this]() { back_to_home(); });
    connect(ui.btn1_back_to_home, &QPushButton::clicked, [this]() { back_to_home(); });

    // 取物开箱按钮事件
    connect(ui.btn1_fetch_back_fee, &QPushButton::clicked, [=]() { fetch_back_fee(); });
    connect(ui.btn1_temporary_fetch, &QPushButton::clicked, [=]() { fetch_temporary(); });
    connect(ui.btn1_end_use, &QPushButton::clicked, [=]() { fetch_end_use(); });

    // 支付方式选择按钮事件
    auto pfunc = [=](QWidget* p) {
        if (p == Q_NULLPTR)
        {
            return;
        }

        auto cl = p->children();
        for (int i = 0; i < cl.size(); i++)
        {
            QWidget* w = qobject_cast<QWidget*>(cl.at(i));
            if (w != Q_NULLPTR && w != p)
            {
                //w->setAttribute(Qt::WA_TransparentForMouseEvents, true);
            }
        }
    };
    pfunc(ui.wnd_paytype_cash);
    pfunc(ui.wnd_paytype_alipay);
    pfunc(ui.wnd_paytype_wechatpay);
    ui.wnd_paytype_cash->installEventFilter(this);
    ui.wnd_paytype_alipay->installEventFilter(this);
    ui.wnd_paytype_wechatpay->installEventFilter(this);
    ui.wnd_paytype_onecode->installEventFilter(this);

    // 支付平台订单查询定时器
    timer_payplat_->setInterval(5 * 1000);
    connect(timer_payplat_, &QTimer::timeout, [=]() { event_payplat_polling(); });

    // install event filter
    ui.wnd_locker_small->installEventFilter(this);
    ui.wnd_locker_medium->installEventFilter(this);
    ui.wnd_locker_large->installEventFilter(this);
    ui.wnd_locker_extralarge->installEventFilter(this);

    // 隐藏价格信息
    ui.btn1_fetch_back_fee->hide();

    // 禁用键盘
    ui.edt_confirm_no->setProperty("noinput", true);
    ui.edt_set_no->setProperty("noinput", true);
    ui.edt_confirm_pwd->setProperty("noinput", true);
    ui.edt_set_pwd->setProperty("noinput", true);
    ui.edt_fetch_auth_no->setProperty("noinput", true);
    ui.edt_fetch_auth_pwd->setProperty("noinput", true);
}

void MainWnd::init_timer()
{
    connect(timer_, &QTimer::timeout, this, [&]() {
        if (!timer_flag_)
        {
            return;
        }

        if (timer_cnt_ <= 0)
        {
            back_to_home();
            return;
        }

        ui.lb_timer->setText(QString::number(timer_cnt_));
        timer_cnt_ -= 1;
        timer_cnt_ = timer_cnt_ > 0 ? timer_cnt_ : 0;
    });
}

void MainWnd::reset_timer(bool flag, int32_t itl)
{
    timer_flag_ = flag;
    timer_cnt_ = itl;

    ui.lb_timer->setText(flag ? QString::number(itl) : QString(""));
}

void MainWnd::set_current_work_mode(int32_t mode)
{
    mode_current_ = (EWorkMode)mode;
    switch (mode)
    {
    case EWorkMode_Deposit:
        reset_current_session();
        set_current_status(EWF_DepositSelectSize);
        break;
    case EWorkMode_Fetch:
        reset_current_session();
        set_current_status(EWF_FetchAuthPwd);
        break;
    default:
        return;
    }

    // 根据配置文件，更新界面
    ui.wnd_paytype_alipay->setEnabled(APPMODEL()->Config().payment.enable_alipay == 1);
    ui.wnd_paytype_wechatpay->setEnabled(APPMODEL()->Config().payment.enable_wechatpay == 1);
    ui.wnd_paytype_cash->setEnabled(APPMODEL()->Config().payment.enable_cash == 1);

    // 重启倒计时定时器
    timer_->stop();
    timer_->start(1000);
}

void MainWnd::set_current_status(int32_t ewf, bool back_flag)
{
    if (ewf_current_ == ewf)
    {
        return;
    }

    // stack last view
    if (!back_flag)
    {
        ewf_stack_.push(ewf_current_);
    }

    // 切换页面
    ewf_current_ = (EWF)ewf;
    ui.wnd_content->setCurrentIndex(ewf_current_);

    switch (ewf)
    {
    case EWF_DepositSelectSize:
    {
        // 箱型选择页面
        // 查询系统是否配置了对应类型的箱型
        zl::LockerVec s_all, m_all, l_all, e_all;
        zl::CCabinetManager::Instance()->GetLockersByType(s_all, zl::ELockerType_Small);
        zl::CCabinetManager::Instance()->GetLockersByType(m_all, zl::ELockerType_Medium);
        zl::CCabinetManager::Instance()->GetLockersByType(l_all, zl::ELockerType_Large);
        zl::CCabinetManager::Instance()->GetLockersByType(e_all, zl::ELockerType_ExtraLarge);
        ui.wnd_locker_small->setVisible(!(s_all.size() == 0));
        ui.wnd_locker_medium->setVisible(!(m_all.size() == 0));
        ui.wnd_locker_large->setVisible(!(l_all.size() == 0));
        ui.wnd_locker_extralarge->setVisible(!(e_all.size() == 0));

        // 查询系统设置的各个箱型的剩余可用格口的数量
        int32_t mask =
                zl::ELockerStatus_Error |
                zl::ELockerStatus_Expired |
                zl::ELockerStatus_Item |
                zl::ELockerStatus_Locked |
                zl::ELockerStatus_Occupied;
        zl::LockerVec s, m, l, e;
        zl::CCabinetManager::Instance()->GetLockersByType(s, zl::ELockerType_Small, mask);
        zl::CCabinetManager::Instance()->GetLockersByType(m, zl::ELockerType_Medium, mask);
        zl::CCabinetManager::Instance()->GetLockersByType(l, zl::ELockerType_Large, mask);
        zl::CCabinetManager::Instance()->GetLockersByType(e, zl::ELockerType_ExtraLarge, mask);
        ui.lb_locker_available_extralarge->setText(tr("Available: %1").arg(e.size()));
        ui.lb_locker_available_large->setText(tr("Available: %1").arg(l.size()));
        ui.lb_locker_available_medium->setText(tr("Available: %1").arg(m.size()));
        ui.lb_locker_available_small->setText(tr("Available: %1").arg(s.size()));

        // 播放语音
        if(s.size() == 0 && m.size() == 0 && l.size() == 0 && e.size() == 0)
        {
            zl::CAudioBroadcast::Instance()->Play("No available boxes.mp3");
        }
        else
        {
            zl::CAudioBroadcast::Instance()->Play("Box type selection.mp3");
        }

        reset_timer(true, itl_.page_deposit_selectsize);
        break;
    }
    case EWF_DepositSetNo:
        // 设置手机尾号页面
        // audio play
        zl::CAudioBroadcast::Instance()->Play("Enter tail number.mp3");
        ui.edt_set_no->setFocus();
        ui.edt_set_no->clear();
        ui.edt_confirm_no->clear();

        reset_timer(true, itl_.page_deposit_setno);
        break;
    case EWF_DepositSetPwd:
        // 设置密码页面
        // audio play
        zl::CAudioBroadcast::Instance()->Play("Setting Password.mp3");
        ui.edt_set_pwd->setFocus();
        ui.edt_set_pwd->clear();
        ui.edt_confirm_pwd->clear();

        reset_timer(true, itl_.page_deposit_setpwd);
        break;
    case EWF_OpenTips:
        // audio play
        zl::CAudioBroadcast::Instance()->Play("The box door is open.mp3");
        reset_timer(true, itl_.page_deposit_open);
        break;
    case EWF_FetchAuthPwd:
        // audio play
        zl::CAudioBroadcast::Instance()->Play("Enter tail number password.mp3");
        ui.edt_fetch_auth_no->clear();
        ui.edt_fetch_auth_pwd->clear();
        ui.edt_fetch_auth_no->setFocus();

        reset_timer(true, itl_.page_fetch_authpwd);
        break;
    case EWF_FetchOpen:
        // audio play
        zl::CAudioBroadcast::Instance()->Play("Halfway fetch or end.mp3");
        reset_timer(true, itl_.page_fetch_open);
        break;
    case EWF_PayType:
        // audio play
        zl::CAudioBroadcast::Instance()->Play("Choose payment method.mp3");
        ui.wnd_paytype_cash->hide();
        ui.wnd_paytype_alipay->hide();
        ui.wnd_paytype_wechatpay->hide();
        ui.wnd_paytype_onecode->hide();

        reset_timer(true, itl_.page_paytype);
        if(APPMODEL()->Config().payment.enable_cash == 1)
        {
            ui.wnd_paytype_cash->show();
        }
        if(APPMODEL()->Config().payment.enable_alipay == 1)
        {
            ui.wnd_paytype_alipay->show();
        }
        if(APPMODEL()->Config().payment.enable_wechatpay == 1)
        {
            ui.wnd_paytype_wechatpay->show();
        }
        if(APPMODEL()->Config().payment.enable_onecode == 1)
        {
            ui.wnd_paytype_onecode->show();
        }

        break;
    case EWF_PayInfo:
        // audio play
        if (session_->paid.pay_mode == PAYMODE_CASH)
        {
            zl::CAudioBroadcast::Instance()->Play("Cash Payment.mp3");
        }
        else
        {
            zl::CAudioBroadcast::Instance()->Play("Sweep Payment.mp3");
        }

        // todo
        reset_timer(true, itl_.page_payinfo);
        break;
    default:
        back_to_home();
        break;
    }
}

void MainWnd::reset_current_session()
{
    session_->order = zl::COrderManager::Instance()->CreateOrder();
    session_->paid = zl::PaidDetail();
}

bool MainWnd::check_userid(QString no1, QString no2)
{
    if(no1.size() != 4 || no1 != no2)
    {
        return false;
    }
    return true;
}

bool MainWnd::check_password(QString pw1, QString pw2)
{
    if(pw1.size() != 6 || pw1 != pw2)
    {
        return false;
    }

    if(std::regex_match(pw1.toStdString(), regex("(\\d)\\1{5}")))
    {
        return false;
    }
    if(pw1 == "123456" || pw1 == "654321")
    {
        return false;
    }

    return true;
}

void MainWnd::set_no_finished()
{
    // 清除用户输入
    auto no1 = ui.edt_set_no->text();
    auto no2 = ui.edt_confirm_no->text();
    ui.edt_set_no->clear();
    ui.edt_confirm_no->clear();

    // 检查用户输入的参数是否合法
    if(!check_userid(no1, no2))
    {
        CToastBox::Error(this, tr(""), tr("There is an error occured, please try again"));
        return ;
    }

    // 跳转到设置密码页面
    session_->order.user_id = no1.toStdString();
    set_current_status(EWF_DepositSetPwd);
}

void MainWnd::set_pwd_finished()
{
    // 清除用户输入
    auto pwd1 = ui.edt_set_pwd->text();
    auto pwd2 = ui.edt_confirm_pwd->text();
    ui.edt_set_pwd->clear();
    ui.edt_confirm_pwd->clear();

    // 检查用户输入的参数是否合法
    if(!check_password(pwd1, pwd2))
    {
        CToastBox::Error(this, tr(""), tr("There is an error occured, please try again"));
        return ;
    }

    // 密码有效性检查
    zl::Order tmp_order;
    auto ret = zl::COrderManager::Instance()->GetOrderByUser(tmp_order, session_->order.user_id, pwd1.toStdString());
    if (ret == zl::EResult_Success)
    {
        // 手机尾号，密码重复
        CToastBox::Error(this, tr(""), tr("There is an error occured, please try again"));
        return;
    }

    // 设置密码完成，进入存物预处理流程
    session_->order.user_code = pwd1.toStdString();
    deposit_preprocessor();
}

void MainWnd::deposit_preprocessor()
{
    // 获取当前对应格口的付费方案ID
    auto planid = APPMODEL()->GetLockersPaymentInfo(session_->order.box_type);
    // 更新超时时间为免费试用时长
    session_->order.exp_time = zl::CPaymentManager::Instance()->GetTrailDuration(planid);
    // 检查是否需要预付费，不需要预付费直接跳转到开箱流程
    auto amount = zl::CPaymentManager::Instance()->Calculate(planid, session_->order);
    if (amount <= 0)
    {
        deposit_finished();
        return;
    }

    // 存物时需要预付费，进入付费流程
    session_->paid.order_id = session_->order.order_id;
    session_->paid.fee_paid = 0;
    session_->paid.fee_total = amount;
    set_current_status(EWF_PayType);
}

void MainWnd::deposit_finished()
{
    // 保存订单信息
    auto ret = zl::COrderManager::Instance()->BeginOrder(session_->order);
    if (ret != zl::EResult_Success)
    {
        CToastBox::Error(this, tr("Operation failed"), tr("Save order details failed"));
        return;
    }

    // 设置格口状态未占用状态
    zl::CCabinetManager::Instance()->SetLockerStatus(session_->order.box_no, zl::ELockerStatus_Occupied, true);

    // 记录日志信息
    session_->log = zl::COperLogManager::Instance()->CreateOperLog();
    session_->log.cabinet_no = session_->order.cabinet_no;
    session_->log.box_no = session_->order.box_no;
    if(session_->paid.pay_mode == "0")
    {
        session_->log.action = tr("Cash Payment Inventory Opening").toStdString();
    }
    else if(session_->paid.pay_mode == "1")
    {
        session_->log.action = tr("WeChat Payment Inventory Opening").toStdString();
    }
    else if(session_->paid.pay_mode == "2")
    {
        session_->log.action = tr("Alipay Payment Inventory Opening").toStdString();
    }
    else
    {
        session_->log.action = tr("Inventory Opening").toStdString();
    }
    session_->log.type = tr("user").toStdString();
    session_->log.account = session_->order.user_id;
    zl::COperLogManager::Instance()->CommitOperLog(session_->log);

    // 打开箱门跳转页面
    ret = zl::CCabinetManager::Instance()->OpenBox(session_->order.box_no);
    open_locker_tips(session_->order.box_no, ret == zl::EResult_Success);
}

void MainWnd::get_auth_finished()
{
    // 清除用户输入
    auto no = ui.edt_fetch_auth_no->text();
    auto pwd = ui.edt_fetch_auth_pwd->text();
    ui.edt_fetch_auth_no->clear();
    ui.edt_fetch_auth_pwd->clear();

    // 检查用户输入的参数是否合法
    if (no.size() != 4 || pwd.size() != 6)
    {
        CToastBox::Error(this, tr("Operation failed"), tr("Invalid phone no or password"));
        return;
    }

    // 验证用户输入的手机号和密码
    zl::Order tmp_order;
    auto ret = zl::COrderManager::Instance()->GetOrderByUser(tmp_order, no.toStdString(), pwd.toStdString());
    if (ret != zl::EResult_Success)
    {
        // 未找到对应的订单信息
        // CToastBox::Error(this, tr("Operation failed"), tr("Wrong phone no or password"));
        // return;

        // 发送异柜查询订单请求
        CToastBox::Info(this, tr("Tips"), tr("Searching order details, please wait..."));
        QTimer::singleShot(2 * 1000, [=]() {
            auto ret = plat_api_->RequestOrderDetails(CabinetID(), no.toStdString(), pwd.toStdString());
            if (ret != zl::IPlatformProxyInterface::EPlatError_Success)
            {
                // 发起异柜请求失败
                CToastBox::Error(this, tr("Operation failed"), tr("Wrong phone no or password"));
                return;
            }
        });
        return;
    }

    // 验证通过
    session_->order = tmp_order;
    fetch_preprocessor();
}

void MainWnd::fetch_preprocessor()
{
    // 取物身份验证通过，显示用户使用信息
    auto bdt = QDateTime::fromString(session_->order.begin_time.c_str(), "yyyy-MM-dd hh:mm:ss");
    auto zdt = QTime({0, 0, 0}).addSecs(bdt.secsTo(QDateTime::currentDateTime()));
    auto cnt = bdt.secsTo(QDateTime::currentDateTime());
    auto tmpd = cnt / (24 * 60 * 60);
    auto tmph = zdt.hour();
    auto tmpm = zdt.minute();

    auto get_order_status_string = [](int32_t status) -> QString {
        switch (status)
        {
        case zl::EOrderStatus_Canceled:     return tr("Status Canceled");
        case zl::EOrderStatus_Completed:    return tr("Status Completed");
        case zl::EOrderStatus_Error:        return tr("Status Error");
        case zl::EOrderStatus_Expired:      return tr("Status Expired");
        case zl::EOrderStatus_Finished:     return tr("Status Finished");
        case zl::EOrderStatus_Locked:       return tr("Status Locked");
        case zl::EOrderStatus_ManualFinished: return tr("Status ManualFinished");
        case zl::EOrderStatus_Prepared:     return tr("Status Prepared");
        case zl::EOrderStatus_Using:        return tr("Status using");
        default:
            return tr("Status Unknown");
        }
    };

    ui.lb_info_locker_no->setText(QString("%1").arg(session_->order.box_no + APPMODEL()->CabinetInfo().tag_number));
    ui.lb_info_begin_time->setText(QString("%1").arg(session_->order.begin_time.c_str()));
    ui.lb_info_expire_time->setText(QString("%1").arg(session_->order.exp_time.c_str()));
    ui.lb_info_spend_time->setText(tr("%1 days %2 hours %3 minutes").arg(tmpd).arg(tmph).arg(tmpm));
    ui.lb_info_order_status->setText(QString("%1").arg(get_order_status_string(session_->order.status)));

    // 计算费用信息
    auto planid = APPMODEL()->GetLockersPaymentInfo(session_->order.box_type);
    auto fee = zl::CPaymentManager::Instance()->Calculate(planid, session_->order);
    // 如果需要收费则，只显示补交费用按钮
    if (fee > 0)
    {
        ui.btn1_fetch_back_fee->setVisible(true);
        ui.btn1_end_use->setVisible(false);
        ui.btn1_temporary_fetch->setVisible(false);
        ui.label_17->setVisible(true);
        ui.lb_info_predict_amount->setVisible(true);
        ui.lb_info_predict_amount->setText(tr("%1 yuan").arg((float)fee / 100.0));
    }
    else
    {
        ui.btn1_fetch_back_fee->setVisible(false);
        ui.btn1_end_use->setVisible(true);
        ui.btn1_temporary_fetch->setVisible(true);
        ui.label_17->setVisible(false);
        ui.lb_info_predict_amount->setVisible(false);
    }

    // 保存费用信息，跳转到取物开箱页面
    session_->paid.order_id = session_->order.order_id;
    session_->paid.fee_paid = 0;
    session_->paid.fee_total = fee;
    set_current_status(EWF_FetchOpen);
}

void MainWnd::fetch_temporary()
{
    // 新增开箱记录
    session_->log = zl::COperLogManager::Instance()->CreateOperLog();
    session_->log.cabinet_no = session_->order.cabinet_no;
    session_->log.box_no = session_->order.box_no;
    if(session_->paid.pay_mode == "0")
    {
        session_->log.action = tr("Cash Payment Opens Midway").toStdString();
    }
    else if(session_->paid.pay_mode == "1")
    {
        session_->log.action = tr("Wechat Payment Opens Midway").toStdString();
    }
    else if(session_->paid.pay_mode == "2")
    {
        session_->log.action = tr("Alipay Payment Opens Midway").toStdString();
    }
    else
    {
        session_->log.action = tr("Opens Midway").toStdString();
    }
    session_->log.type = tr("user").toStdString();
    session_->log.account = session_->order.user_id;
    zl::COperLogManager::Instance()->CommitOperLog(session_->log);

    // 用户选择中途取物，只打开箱门，不做其他处理
    auto ret = zl::CCabinetManager::Instance()->OpenBox(session_->order.box_no);
    // 显示开箱提示页面
    open_locker_tips(session_->order.box_no, ret == zl::EResult_Success);
}

void MainWnd::fetch_end_use()
{
    // 用户选择结束使用，打开箱门，结束订单
    auto ret = zl::COrderManager::Instance()->FinishOrder(session_->order);
    if (ret != zl::EResult_Success)
    {
        // 结束订单失败
        CToastBox::Error(this, tr("Operation failed"), tr("Finished order failed, please contact the administrator"));
        return;
    }

    // 更新格口状态
    zl::CCabinetManager::Instance()->SetLockerStatus(session_->order.box_no, zl::ELockerStatus_Occupied, false);

    // 添加开箱日志
    session_->log = zl::COperLogManager::Instance()->CreateOperLog();
    session_->log.cabinet_no = session_->order.cabinet_no;
    session_->log.box_no = session_->order.box_no;
    if(session_->paid.pay_mode == "0")
    {
        session_->log.action = tr("Cash Payment Extract Opening").toStdString();
    }
    else if(session_->paid.pay_mode == "1")
    {
        session_->log.action = tr("WeChat Payment Extract Opening").toStdString();
    }
    else if(session_->paid.pay_mode == "2")
    {
        session_->log.action = tr("Alipay Payment Extract Opening").toStdString();
    }
    else
    {
        session_->log.action = tr("Extract Opening").toStdString();
    }

    session_->log.type = tr("user").toStdString();
    session_->log.account = session_->order.user_id;
    zl::COperLogManager::Instance()->CommitOperLog(session_->log);

    // 开箱，显示开箱提示页面
    ret = zl::CCabinetManager::Instance()->OpenBox(session_->order.box_no);
    open_locker_tips(session_->order.box_no, ret == zl::EResult_Success);
}

void MainWnd::fetch_back_fee()
{
    // 用户选择补缴费用，跳转到支付方式选择页面
    set_current_status(EWF_PayType);
}

void MainWnd::open_locker_tips(int32_t no, bool flag)
{
    // 显示开箱提示页面
    if (flag)
    {
        ui.lb_open_tips->setText(QString("<html><head/><body><p><span style=\" font-size:32px;font-weight:600;\">")
            + tr("Locker [ %1 ] is opened").arg(no + APPMODEL()->CabinetInfo().tag_number)
            + QString("<br></span></p><p><br/></p><p><span style=\"font-size:24px;\">")
            + tr("For the safety of your belongings, please close the door after using the storage box. \
                  If you encounter problems with the door opening, please contact the administrator in time.")
            + QString("</span></p></body></html>"));
    }
    else
    {
        ui.lb_open_tips->setText(QString("<html><head/><body><p><span style=\" font-size:32px;font-weight:600;\">")
            + tr("Open Locker [ %1 ] failed").arg(no + APPMODEL()->CabinetInfo().tag_number)
            + QString("<br></span></p><p><br/></p><p><span style=\"font-size:24px;\">")
            + tr("For the safety of your belongings, please close the door after using the storage box. \
                  If you encounter problems with the door opening, please contact the administrator in time.")
            + QString("</span></p></body></html>"));
    }

    set_current_status(EWF_OpenTips);
}

void MainWnd::payment_complete(bool flag)
{
    // 保存支付信息
    if (session_->paid.fee_paid > 0)
    {
        session_->paid.cabinet_id = session_->order.cabinet_no;
        session_->paid.box_id = session_->order.box_no;
        session_->paid.confirmed = 0;
        session_->paid.usestate = "1";
        session_->paid.pay_time = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss").toStdString();
        zl::CPaymentManager::Instance()->CreatePaidDetails(session_->paid);
    }

    // 未完成的订单流程（支付未完成但已支付部分金额）
    if (!flag) return;

    // 支付成功，跳转到之前页面
    ui.lb_pay_tips->setText("Operation complete");
    if (mode_current_ == EWorkMode_Deposit)
    {
        deposit_finished();
        return;
    }
    else if (mode_current_ == EWorkMode_Fetch)
    {
        ui.label_17->setVisible(false);
        ui.lb_info_predict_amount->setVisible(false);
        ui.btn1_end_use->setVisible(true);
        ui.btn1_fetch_back_fee->setVisible(false);
        ui.btn1_temporary_fetch->setVisible(false);
        set_current_status(EWF_FetchOpen);
    }
    else
    {
        back_to_home();
    }
}

void MainWnd::event_paytype_selected(const std::string &type)
{
    // 保存用户选择的支付方式
    session_->paid.pay_mode = type;
    session_->paid.pay_order_id = zl::COrderManager::GeneratedOrderID();

    ui.lb_amount_total->setText(tr("%1 yuan").arg((float)session_->paid.fee_total / 100.0));
    ui.lb_amount_paid->setText(tr("0.00 yuan"));

    // 根据用户选择的支付方式，发起支付请求
    zl::PayRequest req;
    req.type = zl::EPayRequestTypeCreate;
    req.order_id = session_->paid.pay_order_id;
    req.total_fee = QString::number(session_->paid.fee_total).toStdString();

    if (type == PAYMODE_CASH)
    {
        // 启用纸币器
        ui.lb_pay_tips->setText(tr("Receiving notes...."));
        ui.wnd_card_qrcode->setVisible(false);

        // 纸币器打开失败，提示错误
        if (validator_ == nullptr || validator_->Enable() != zl::EResult_Success)
        {
            CToastBox::Warn(this, tr(""),
                tr("Enable validator failed, please try another payment method"));
            return;
        }
    }
    else if (type == PAYMODE_ALIPAY)
    {
        req.pay_type = "00";
        ui.lb_qrcode->clear();
        ui.lb_pay_tips->setText(tr("Requesting QRcode, please wait..."));
        ui.wnd_card_qrcode->setVisible(true);
        zl::GetPayplatInterface()->CreateOrder(req);
    }
    else if (type == PAYMODE_WECHATPAY)
    {
        req.pay_type = "01";
        ui.lb_qrcode->clear();
        ui.lb_pay_tips->setText(tr("Requesting QRcode, please wait..."));
        ui.wnd_card_qrcode->setVisible(true);
        zl::GetPayplatInterface()->CreateOrder(req);
    }
    else if (type == PAYMODE_ONECODE)
    {
        req.pay_type = "09";
        ui.lb_pay_tips->setText(tr("Requesting QRcode, please wait..."));
        ui.wnd_card_qrcode->setVisible(true);
        zl::GetPayplatInterface()->CreateOrder(req);
    }
    else
    {
        CToastBox::Error(this, "", tr("Opeartion failed, Unknow pay type"));
        return;
    }

    // 发起支付请求, 跳转到支付信息页面
    set_current_status(EWF_PayInfo);
}

void MainWnd::event_payplat_polling()
{
    // 定时向支付服务器发起支付结果查询请求
    zl::PayRequest req;
    req.type = zl::EPayRequestTypeCheck;
    req.fee_type = "00";
    req.order_id = session_->paid.pay_order_id;
    req.trade_no = session_->paid.pay_trade_no;
    if (session_->paid.pay_mode == PAYMODE_ALIPAY)
    {
        req.pay_type = "00";
    }
    else if (session_->paid.pay_mode == PAYMODE_WECHATPAY)
    {
        req.pay_type = "01";
    }
    else
    {
        req.pay_type = "09";
    }
    zl::GetPayplatInterface()->CheckOrder(req);
}

void MainWnd::event_lockertype_selected(int32_t type)
{
    auto box_no = zl::CCabinetManager::Instance()->GetAvilableLocker((zl::ELockerType)type);
    if (box_no == -1)
    {
        CToastBox::Error(this, tr("Allocation failure"), tr("No more available lockers"));
        return;
    }

    // 分配成功
    session_->order.box_no = box_no;
    session_->order.box_type = type;

    // 页面跳转
    set_current_status(EWF_DepositSetNo);
}

bool MainWnd::eventFilter(QObject *watched, QEvent *event)
{
    // 过滤掉禁用状态和隐藏的控件
    QWidget* tmpw = qobject_cast<QWidget*>(watched);
    if (tmpw != Q_NULLPTR && (!tmpw->isEnabled() || !tmpw->isVisible()))
    {
        return QWidget::eventFilter(watched, event);
    }

    if (ui.wnd_locker_small == qobject_cast<QWidget*>(watched))
    {
        if (event->type() == QEvent::MouseButtonPress)
        {
            event_lockertype_selected(zl::ELockerType_Small);
        }
        return true;
    }
    else if (ui.wnd_locker_medium == qobject_cast<QWidget*>(watched))
    {
        if (event->type() == QEvent::MouseButtonPress)
        {
            event_lockertype_selected(zl::ELockerType_Medium);
        }
        return true;
    }
    else if (ui.wnd_locker_large == qobject_cast<QWidget*>(watched))
    {
        if (event->type() == QEvent::MouseButtonPress)
        {
            event_lockertype_selected(zl::ELockerType_Large);
        }
        return true;
    }
    else if (ui.wnd_locker_extralarge == qobject_cast<QWidget*>(watched))
    {
        if (event->type() == QEvent::MouseButtonPress)
        {
            event_lockertype_selected(zl::ELockerType_ExtraLarge);
        }
        return true;
    }
    else if (ui.wnd_paytype_cash == qobject_cast<QWidget*>(watched))
    {
        if (event->type() == QEvent::MouseButtonPress)
        {
            event_paytype_selected(PAYMODE_CASH);
            return true;
        }
        return false;
    }
    else if (ui.wnd_paytype_alipay == qobject_cast<QWidget*>(watched))
    {
        if (event->type() == QEvent::MouseButtonPress)
        {
            event_paytype_selected(PAYMODE_ALIPAY);
            return true;
        }
        return false;
    }
    else if (ui.wnd_paytype_wechatpay == qobject_cast<QWidget*>(watched))
    {
        if (event->type() == QEvent::MouseButtonPress)
        {
            event_paytype_selected(PAYMODE_WECHATPAY);
            return true;
        }
        return false;
    }
    else if (ui.wnd_paytype_onecode == qobject_cast<QWidget*>(watched))
    {
        if (event->type() == QEvent::MouseButtonPress)
        {
            event_paytype_selected(PAYMODE_ONECODE);
            return true;
        }
        return false;
    }

    return QWidget::eventFilter(watched, event);
}
